//call,bind,apply 的区别
//call和apply都是在调用函数时改变this的指向, bind是产生新的函数并绑定this;
//call和apply的区别是:第一个参数都是要绑定的this,但是 apply第二个参数(函数的参数)为数组,call是多个的;
function call(fn, obj, ...arg) {
  if (obj == undefined || obj == null) {
    obj = globalThis;
  }
  obj.tmp = fn;
  let result = obj.tmp(...arg);
  delete obj.tmp;
  return result;
}
function bind(fn, obj, ...args) {
  return function (...args2) {
    return call(fn, obj, ...args, ...args2);
  };
}

// debounce 防抖,多次只执行最后一次,返回结果是一个函数
function debounce(callback, wait) {
  let timer = null;
  return function (e) {
    // 如果已经有
    if (timer !== null) {
      clearTimeout(timer);
    } else {
      // 如果没有,开启定时
      timer = setTimeout(() => {
        callback.call(this, e);
        timer = null;
      }, wait);
    }
  };
}

// trottle 节流,每隔一段时间执行一次
function trottle(callback, wait) {
  let start = 0;
  return function (e) {
    let now = Date.now();
    if (now - start >= wait) {
      callback.call(this, e);
      start = now;
    }
  };
}

//clone1 clone2
function clone1(target) {
  if (typeof target == "object" && typeof target !== null) {
    if (Array.isArray(target)) {
      return [...target];
    } else {
      return { ...target };
    }
  } else {
    return target;
  }
}

function clone2(target) {
  if (typeof target == "object" && typeof target !== null) {
    let result = Array.isArray(target) ? [] : {};
    for (let key in target) {
      if (target.hasOwnProperty(key)) {
        result[key] = target[key];
      }
    }
  } else {
    return target;
  }
}
